#ifndef LOG_H
#define LOG_H

#include <memory>
#include <thread>
#include <string>
#include <mutex>
#include <sys/time.h>
#include <string.h>
#include <stdarg.h>
#include <sys/stat.h>
#include <assert.h>

#include "../buffer/buffer.h"
#include "blockqueue.h"

class Log {
public:
    void init(int level = 1, const char* path = "./log", 
        const char* suffix = ".log", int maxQueueSize = 1024);

    static Log* instance();
    static void flushLogThread();

    void write(int level, const char* format, ...);
    void flush();

    int getLevel();
    void setLevel(int level);
    bool isOpen();

private:
    Log();
    ~Log();
    void appendLogLevelTitle(int level);
    void asyncWrite();

private:
    static const int MAX_LOG_PATH_LEN = 256;
    static const int MAX_LOG_NAME_LEN = 256;
    static const int MAX_LINES = 50000;

    const char* path_;
    const char* suffix_;

    int maxlines_;
    int curlines_;
    int curDays_;

    bool isOpen_;

    Buffer buff_;
    int level_;
    bool isAsync_;

    FILE* fp_;
    std::unique_ptr<BlockQueue<std::string>> deque_;
    std::unique_ptr<std::thread> writeThread_;
    std::mutex mtx_;
};

#define LOG_BASE(level, format, ...) \
    do {\
        Log* log = Log::instance();\
        if(log->isOpen() && log->getLevel() <= level) {\
            log->write(level, format, ##__VA_ARGS__);\
            log->flush();\
        }\
    } while(0);

#define LOG_DEBUG(format, ...) do {LOG_BASE(0, format, ##__VA_ARGS__)} while(0);
#define LOG_INFO(format, ...) do {LOG_BASE(1, format, ##__VA_ARGS__)} while(0);
#define LOG_WARN(format, ...) do {LOG_BASE(2, format, ##__VA_ARGS__)} while(0);
#define LOG_ERROR(format, ...) do {LOG_BASE(3, format, ##__VA_ARGS__)} while(0);

#endif